home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / misc / emu / msh-156.lha / han / date.c next >
C/C++ Source or Header  |  1996-12-22  |  11KB  |  432 lines

  1. /*-
  2.  * $Id: date.c,v 1.56 1996/12/22 00:22:33 Rhialto Rel $
  3.  * $Log: date.c,v $
  4.  * Revision 1.56  1996/12/22  00:22:33  Rhialto
  5.  * Cosmetics only.
  6.  *
  7.  * Revision 1.55  1993/12/30  23:28:00    Rhialto
  8.  * Freeze for MAXON5.
  9.  *
  10.  * Revision 1.54  1993/06/24  05:12:49    Rhialto
  11.  * DICE 2.07.54R.
  12.  *
  13.  * Revision 1.53  92/10/25  02:43:23  Rhialto
  14.  * No real change.
  15.  *
  16.  * Revision 1.52  92/09/06  00:22:03  Rhialto
  17.  * Didn't believe in leap days and some other days.
  18.  *
  19.  * Revision 1.51  92/04/17  15:38:43  Rhialto
  20.  * Freeze for MAXON3.
  21.  *
  22.  * Revision 1.50  92/02/12  21:24:58  Rhialto
  23.  * New date-to-days function.
  24.  *
  25.  * Revision 1.46  91/10/06  18:27:01  Rhialto
  26.  *
  27.  * Freeze for MAXON
  28.  *
  29.  * Revision 1.42  91/06/14  00:09:48  Rhialto
  30.  * DICE conversion
  31.  *
  32.  * Revision 1.40  91/03/03  17:55:18  Rhialto
  33.  * Freeze for MAXON
  34.  *
  35.  * Revision 1.32  90/11/23  23:55:51  Rhialto
  36.  * Prepare for syslog
  37.  *
  38.  * Revision 1.30  90/06/04  23:18:11  Rhialto
  39.  * Release 1 Patch 3
  40.  *
  41.  * DATE.C
  42.  *
  43.  * Two date conversion routines: DateStamp <-> MSDOS date/time.
  44.  *
  45.  * This code is (C) Copyright 1989-1993 by Olaf Seibert. All rights reserved.
  46.  * May not be used or copied without a licence.
  47.  */
  48.  
  49. #include "han.h"
  50. #ifndef LIBRARIES_DOS_H
  51. #include <libraries/dos.h>
  52. #endif
  53.  
  54. #if HDEBUG
  55. #   include "syslog.h"
  56. #else
  57. #   define    debug(x)
  58. #endif
  59.  
  60. Prototype void ToDateStamp(struct DateStamp *datestamp, word date, word time);
  61. Prototype void ToMSDate(word *date, word *time, struct DateStamp *datestamp);
  62.  
  63. long unixdays(int year, int month, int day);
  64. void YrMoDa(long intdat, long *yr, long *mo, long *da);
  65.  
  66. /*
  67. Article 2344 of alt.sources.d:
  68. Path: wn1.sci.kun.nl!sun4nl!mcsun!uunet!munnari.oz.au!yoyo.aarnet.edu.au!sirius.ucs.adelaide.edu.au!amodra
  69. From: amodra@ucs.adelaide.edu.au (Alan Modra)
  70. Newsgroups: alt.sources.d
  71. Subject: Re: timelocal (struct tm to time_t conversion) algorithm...
  72. Message-ID: <5699@sirius.ucs.adelaide.edu.au>
  73. Date: 20 Dec 91 03:27:53 GMT
  74. References: <20169@rpp386.cactus.org>
  75. Organization: Information Technology Division, The University of Adelaide, AUSTRALIA
  76. Lines: 48
  77.  
  78. From article <20169@rpp386.cactus.org>, by jfh@rpp386.cactus.org (John F Haugh II):
  79. > While we are all trotting out our mktime.c de la dia, here is one that
  80.  
  81. Thought I'd trot out my contribution too !
  82.  
  83. The following routine uses a reasonably concise method to convert the
  84. date, which is probably the most awkward part in generating GMT since
  85. 1/1/1970.  Feel free to tack this bit of code in whatever other sources
  86. you like!
  87.  
  88. OIS: 2922 is original_unixdays(1978, 1, 1) so we can use it for
  89.      AmigaDOS dates.
  90.  
  91. #include <stdlib.h>
  92. #include <stdio.h>
  93. */
  94.  
  95.  
  96. long unixdays(int year, int month, int day)
  97. /* converts date to days since 1/1/1970
  98.    no check is made for sensible parameters
  99.    BTW this routine works for dates before 1/1/1970 too
  100.    (The Gregorian calendar only goes back to 1582 though !)
  101. */
  102. {
  103.     if ( (month -= 3) < 0 ) /* 1..12 -> 10,11,0..9 */
  104.     {                /* Puts Feb last since it has 28 days */
  105.     month += 12;        /* Now days per month is 31,30,31,30,31, */
  106.     year -= 1;        /*    (starting from Mar)  31,30,31,30,31, */
  107.     }                /*                 31,28 */
  108. #if 0    /* for those who like calculations ! */
  109.     month *= 31+30+31+30+31;/* Note the pattern. */
  110.     day += month/5;        /* We make use of it here and in the next line */
  111.     if ( month % 5 > 2 ) day += 1;
  112. #else    /* for those who like table look-up ! */
  113.     {
  114.     static const int monthdays[12] = {
  115.         0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337 };
  116.     day += monthdays[month];
  117.     }
  118. #endif
  119.     return (long)(year/4 - year/100 + year/400 + day) + year*365L - 719469L
  120.        - 2922;
  121. }
  122.  
  123.  
  124. #define BASEYEAR        1978
  125. #define DAYS_PER_YEAR        365
  126. #define HOURS_PER_DAY        24
  127. #define MINUTES_PER_HOUR    60
  128. #define SECONDS_PER_MINUTE  60
  129.  
  130. #define DAYS_PER_WEEK        7
  131. #define MONTHS_PER_YEAR     12
  132.  
  133. #define MINUTES_PER_DAY     (MINUTES_PER_HOUR * HOURS_PER_DAY)
  134. #define SECONDS_PER_DAY     ((long) SECONDS_PER_MINUTE * \
  135.                  MINUTES_PER_HOUR * HOURS_PER_DAY)
  136.  
  137. #define LeapYear(year)    ((year & 3) == 0)   /* From 1-Mar-1901 to 28-Feb-2100 */
  138.  
  139. const int daycount[MONTHS_PER_YEAR] = {
  140.     31,    28,    31,    30,    31,    30,
  141.     31,    31,    30,    31,    30,    31
  142. };
  143.  
  144. void
  145. ToDateStamp(datestamp, date, time)
  146. struct DateStamp *datestamp;
  147. word date;
  148. word time;
  149. {
  150.     {
  151.     int hours, minutes, seconds;
  152.  
  153.     seconds = (time & 31) * 2;
  154.     time >>= 5;
  155.     minutes = time & 63;
  156.     time >>= 6;
  157.     hours = time;
  158.  
  159.     datestamp->ds_Minute = MINUTES_PER_HOUR * hours + minutes;
  160.     datestamp->ds_Tick = TICKS_PER_SECOND * seconds;
  161.     }
  162.  
  163.     {
  164.     int        year, month, day;
  165.     int        t;
  166.  
  167.     if (date < DATE_MIN)
  168.         date = DATE_MIN;
  169.  
  170.     day = date & 31;
  171.     date >>= 5;
  172.     month = (date & 15);
  173.     date >>= 4;
  174.     year = date + 1980;
  175.  
  176.     t = daycount[month - 1];
  177.     if (month == 2 && LeapYear(year))
  178.         t++;
  179.     if ((unsigned) month > 12 || (unsigned) day > t) {
  180.         day = 31;
  181.         month = 12;
  182.         year = 1979;
  183.     }
  184.  
  185. #if 1
  186.     datestamp->ds_Days = unixdays(year, month, day);
  187. #else
  188.     {
  189.         ulong i, j, t;
  190.         j = year - BASEYEAR;
  191.  
  192.         /* Get the next lower full leap period (4 years and a day) since ... */
  193.         t = (year - BASEYEAR) & ~3;
  194.         i = t;
  195.         t = (t / 4) * (4 * DAYS_PER_YEAR + 1);
  196.  
  197.         /* t now is the number of days in 4 whole years since ... */
  198.  
  199.         while (i < j) {
  200.         t += DAYS_PER_YEAR;
  201.         if (LeapYear(i + BASEYEAR)) {
  202.             t++;
  203.         }
  204.         i++;
  205.         }
  206.  
  207.         /* t now is the number of days in whole years since ... */
  208.  
  209.         month--;    /* 1..12 -> 0..11 */
  210.         for (i = 0; i < month; i++) {
  211.         t += daycount[i];
  212.         if (i == 1 && LeapYear(year)) {
  213.             t++;
  214.         }
  215.         }
  216.  
  217.         /* t now is the number of days in whole months since ... */
  218.  
  219.         t += day - 1;
  220.  
  221.         /* t now is the number of days in whole days since ... */
  222.  
  223.         datestamp->ds_Days = t;
  224.     }
  225. #endif
  226.     }
  227. }
  228.  
  229. void YrMoDa(long intdat, long *yr, long *mo, long *da);
  230.  
  231. /*
  232. Article 11708 of comp.sys.amiga.programmer:
  233. Path: wn1.sci.kun.nl!sun4nl!mcsun!uunet!elroy.jpl.nasa.gov!decwrl!public!thad
  234. From: thad@public.BTR.COM (Thaddeus P. Floryan)
  235. Newsgroups: comp.sys.amiga.programmer
  236. Subject: Re: Date Conversion..
  237. Message-ID: <5396@public.BTR.COM>
  238. Date: 2 Feb 92 07:43:43 GMT
  239. References: <3125@seti.UUCP>
  240. Organization: BTR Public Access UNIX, Mountain View CA
  241. Lines: 130
  242.  
  243. In article <3125@seti.UUCP> oudejans@bora.inria.fr (Jeroen Oudejans) writes:
  244. >
  245. >Can anybody post me some code which recalculates a 'human readable' date
  246. >from seconds after 1978 ?
  247. >Or is there a library available (i am not using OS2, so can't use Amiga2Date())
  248.  
  249. Enclosed is something I last posted in 1988.  A more-commented version was to
  250. appear in one of Rob Peck's books but for his untimely death July 2, 1990.
  251.  
  252. Thad Floryan [ thad@btr.com (OR) {decwrl, mips, fernwood}!btr!thad ]
  253.  
  254. -------------------- begin enclosure
  255.  
  256. From: thad@cup.portal.com
  257. Newsgroups: comp.sys.amiga.tech
  258. Subject: Re: Decoding a DateStamp
  259. Message-ID: <5276@cup.portal.com>
  260. Date: 10 May 88 09:20:41 GMT
  261.  
  262. The following code may be useful to you.  It's one of several hundreds of
  263. kwik'n'dirty throwaways I did back in '85 when testing every documented
  264. feature of the Amiga.  The "basic" code also works fine on DEC-20, Vax,
  265. AT&T UNIX PC, C64/C128, and every other system I've tried it on.
  266.  
  267. Originally compiled this with Lattice 3.02; to compile with any recent Manx:
  268.  
  269.     CLI> cc +L dater
  270.     CLI> ln dater -lc32
  271.  
  272. Feel welcome to use this example for your own learning; I'm intending this
  273. (along with my complete date arithmetic package) to be part of an article
  274. I intend completing (Real Soon Now :-) along with examples in C, assembler,
  275. Fortran, AmigaBasiC, Modula-2 and Pascal.  This specific example has worked
  276. perfectly thru AmigaDOS 1.0, 1.1, and 1.2 (and presumably 1.3 and beyond).
  277.  
  278. ----------cut 'ere----------
  279. */
  280. #if 0
  281. /* DATER.C     Check out the DateStamp AmigaDOS system function
  282.  *
  283.  *    see page 2-15 in the AmigaDOS Developer's Manual for more info
  284.  */
  285.  
  286. struct DS {         /* DateStamp structure */
  287.    long  NDays;      /* Days from Jan. 1, 1978 (a Sunday) */
  288.    long  NMinutes;   /* Minutes into the current day */
  289.    long  NTicks;     /* Clock ticks (1/50 sec = 1 tick) in current second */
  290. };
  291.  
  292. static char *wkdays[] =
  293. {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
  294.  
  295. static char *mthnam[] =
  296. {"","JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"};
  297.  
  298. main()
  299. {
  300.    void DateStamp(), YrMoDa();
  301.  
  302.    struct DS datime;
  303.    long month, day, year, hour, minute, second;
  304.  
  305.    DateStamp(&datime);
  306.    printf("Days since 1-JAN-78 = %d\n", datime.NDays);
  307.    printf("Minutes into today  = %d\n", datime.NMinutes);
  308.    printf("1/50 secs in minute = %d\n", datime.NTicks);
  309.  
  310.    YrMoDa(datime.NDays, &year, &month, &day);
  311.  
  312.    printf("\nTherefore today is ");
  313.    printf("%s ", wkdays[datime.NDays % 7]);
  314.  
  315.    printf("%d-%s-%d", day, mthnam[month], year);
  316.  
  317.    hour   = datime.NMinutes / 60;
  318.    minute = datime.NMinutes % 60;
  319.    second = datime.NTicks / 50;
  320.    printf(" %2d:%02d:%02d\n", hour, minute, second);
  321.  
  322.    exit(0);
  323. }
  324. #endif
  325. /****************************** YrMoDa **********************************
  326.  *
  327.  *    Extracts the component month, day and year from an AmigaDOS
  328.  *    internal `day number' based from Jan.1, 1978.
  329.  *
  330.  *    The calculations herein use the following assertions:
  331.  *
  332.  *    146097 = number of days in 400 years per 400 * 365.2425 = 146097.00
  333.  *     36524 = number of days in 100 years per 100 * 365.2425 =  36524.25
  334.  *    1461 = number of days in   4 years per     4 * 365.2425 =   1460.97
  335.  *
  336.  *    Thad Floryan, 12-NOV-85
  337.  */
  338.  
  339. #define DDELTA 722449    /* days from Jan.1,0000 to Jan.1,1978 */
  340.  
  341. static int mthvec[] =
  342.    {-1, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364};
  343.  
  344. void YrMoDa(intdat, yr, mo, da)
  345.    long intdat;   /* I: AmigaDOS format, days since 1-JAN-78 */
  346.    long *yr;      /* O: resultant year in form YYYY */
  347.    long *mo;      /* O: resultant month in form MM */
  348.    long *da;      /* O: resultant day of month in form DD */
  349. {
  350.    long jdate, day0, day1, day2, day3;
  351.  
  352.    jdate = intdat + DDELTA;  /* adjust internal date to Julian */
  353.  
  354.    *yr     = (jdate / 146097) * 400;
  355.    day0  = day1 = jdate %= 146097;
  356.    *yr    += (jdate / 36524) * 100;
  357.    day2  = day1 %= 36524;
  358.    *yr    += (day2 / 1461) * 4;
  359.    day3  = day1 %= 1461;
  360.    *yr    += day3 / 365;
  361.    *mo     = 1 + (day1 %= 365);
  362.    *da     = *mo % 30;
  363.    *mo    /= 30;
  364.  
  365.    if ( ( day3 >= 59 && day0 < 59 ) ||
  366.     ( day3 <  59 && (day2 >= 59 || day0 < 59) ) )
  367.       ++day1;
  368.  
  369.    if (day1 > mthvec[1 + *mo]) ++*mo;
  370.    *da = day1 - mthvec[*mo];
  371. }
  372. /* end of DATER.C */
  373.  
  374. /*-------------------- end enclosure */
  375.  
  376. void
  377. ToMSDate(date, time, datestamp)
  378. word *date;
  379. word *time;
  380. struct DateStamp *datestamp;
  381. {
  382.     {
  383.     word hours, minutes, seconds;
  384.  
  385.     hours = datestamp->ds_Minute / MINUTES_PER_HOUR;
  386.     minutes = datestamp->ds_Minute % MINUTES_PER_HOUR;
  387.     seconds = datestamp->ds_Tick / TICKS_PER_SECOND;
  388.  
  389.     *time = (hours << 11) | (minutes << 5) | (seconds / 2);
  390.     }
  391. #if 1
  392.     {
  393.     long year, month, day;
  394.  
  395.     YrMoDa(datestamp->ds_Days, &year, &month, &day);
  396.     *date = ((year - 1980) << 9) | (month << 5) | day;
  397.     }
  398. #else
  399.     {
  400.     long days, i, t;
  401.     int year, month, day;
  402.  
  403.     days = datestamp->ds_Days;
  404.  
  405.     year = BASEYEAR + (days/(4*DAYS_PER_YEAR+1)) * 4;
  406.     days %= 4 * DAYS_PER_YEAR + 1;
  407.     while (days) {
  408.         t = DAYS_PER_YEAR;
  409.         if (LeapYear(year))
  410.             t++;
  411.         if (days < t)
  412.             break;
  413.         days -= t;
  414.         year++;
  415.     }
  416.     days++;
  417.     for (i = 0; i < MONTHS_PER_YEAR; i++) {
  418.         t = daycount[i];
  419.         if (i == 1 && LeapYear(year))
  420.             t++;
  421.         if (days <= t)
  422.             break;
  423.         days -= t;
  424.     }
  425.     month = i + 1;
  426.     day = days;
  427.  
  428.     *date = ((year - 1980) << 9) | (month << 5) | day;
  429.     }
  430. #endif
  431. }
  432.